#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <pthread.h>
#include <netinet/in.h>
#include "msql.h"
#define LENGTH_OF_LISTEN_QUEUE 10


void user_thread(void *arg)
{
	printf("hello welcome to mysql\n");
}

int main()
{
	printf("hello,msql\n");
	load_config();

        int servfd,clifd;
        struct sockaddr_in servaddr,cliaddr;
        if ((servfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
        {
                printf("create socket error!\n");
                exit(1);
        }
	servaddr.sin_family = AF_INET;
	int port = 10086;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = htons(INADDR_ANY);

	int reuse=1;
	setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, &reuse,sizeof(int));

	if (bind(servfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
	{
		printf("bind to port %d failure!\n", port);
		exit(1);
	}

	if (listen(servfd,LENGTH_OF_LISTEN_QUEUE) < 0)
	{
		printf("call listen failure!\n");
		exit(1);
	}

	while (1)
	{
		socklen_t length = sizeof(cliaddr);
		printf("waiting for client to connect!\n");
		clifd = accept(servfd,(struct sockaddr*)&cliaddr,&length);
		if (clifd < 0)
		{
			printf("error comes when call accept!\n");
			continue;
		}
		else
		{
			printf("accept success!\n");
			int pid;
			pthread_create(&pid, NULL, user_thread, clifd);
		}

	}

	close(servfd);


	//connect();
	//execute_create_sql("create table  stu (id int, name char(30), score int)");
	//execute_insert_sql("insert into stu values(112,'first', 222)");	
	//execute_insert_sql("insert into stu values(142,'second', 221)");	
	//execute_insert_sql("insert into stu values(115,'third', 2211)");	
	//execute_select_sql("select * from stu");	
}

int execute_create_sql(MConn *conn, char *sqlstr)
{
	//fixme
	printf("\n%s\n",sqlstr);
	char *buffer = (char *)malloc(4096);
	char name[128];
	char temp[255];
	int position = 0;
	char *table = get_create_table_name(sqlstr);
	if(table == NULL)
	{
		free(buffer);
		return -1;
	}
	sprintf(name, "%s/%s.schemal",g_datadir,table); 
	
	char *p1 = strstr(sqlstr,"(");
	p1++;
	while(*p1 == ' ')
	{
		p1++;
	}
	sprintf(temp,"%s",p1);
	char *column = strtok(temp, ",");
	while(column)
	{
		while(*column == ' ')
		{
			column ++;
			if(column == NULL)
			{
				free(table);
				free(buffer);
				return -1;
			}
		}
		char *delim = strstr(column, " ");
		int size = delim - column ;
		while(*delim == ' ')
		{
			delim ++;
			if(delim == NULL)
			{
				free(table);
				free(buffer);
				return -1;
			}
		}
		if(*delim == 'i')
		{
			*(buffer+position) = 4;
			position +=2;
			*(buffer+position) = 'i';
			position ++;
			strncpy(buffer+position, column, size);
			position += size;
			*(buffer+position) = ';';
			position ++;
		}
		else if(*delim == 'c')
		{
			char *p1 = strstr(delim, "(");
			int length = atoi(p1+1);
			int *temp = (int*)(buffer+position);
			*temp = length;
			position +=2;
			*(buffer+position) = 'c';
                        position ++;
			strncpy(buffer+position, column, size);
			position += size;
			*(buffer+position) = ';';
			position ++;
		}		
		else
		{
			free(table);
			free(buffer);
			return -1;
		}
		column = strtok(NULL, ",");
	}
	position--;
	if(*(buffer+position) == ';')
	{
		*(buffer+position) = 0;
	}

	FILE *fp = fopen(name, "w+b");
	fwrite(buffer, position, 1, fp);
	fclose(fp); 
	free(table);
	free(buffer);
	return 0;
}

char *get_create_table_name(char *sqlstr)
{
	char *p1 = strstr(sqlstr, "table");
	char *p2 = strstr(sqlstr, "(");
	if(p1 == NULL || p2 == NULL || p1 > p2)
		return NULL;
	p1 += 5;
	while(*p1 == ' ')
	{
		p1++;
	}	
	p2--;
	while(*p2 == ' ')
	{
		p2--;
	}
	char *ret = (char*)malloc(p2-p1+2);
	snprintf(ret, p2-p1+2, p1);
	return ret;
}

/*
 * get schemal file name
 * open schemal file
 * do insert
 *
 */

void execute_insert_sql(MConn *conn, char *sqlstr)
{

	// get schemal file name
	printf("\n%s\n",sqlstr);
	char *file = (char*) malloc(512);
	char *name = get_insert_table_name(sqlstr);
	sprintf(file, "%s/%s.schemal", g_datadir, name);


	// read schemal file
	int *schemal = get_schemal(file);
	if(schemal == NULL)
	{
		printf("can't read schemal\n");
		return;
	}

	// output schemal file
	int i = 1;
	printf("table format: ");
	for(;i<schemal[0]*2+1;i+=2)
	{
		printf("%d(%s) ",schemal[i], schemal[i+1] == 0?"int":"char");
	}

	// do insert
	sprintf(file, "%s/%s.data", g_datadir, name);
	do_insert(sqlstr, schemal, file);
	free(name);
}

char** getColumns(char *sqlstr, int size)
{
	char **ret = (char**) malloc (size * (sizeof(char *)));
	char buffer[512];
	memset(buffer,0,512);
	int index = 0;
	char *p1 = strstr(sqlstr, "values");
	char *p2 = strstr(sqlstr, "(");
	char *p3 = strstr(sqlstr, ")");
	if(p1 == NULL || p2 == NULL || p3 == NULL)
		return NULL;
	snprintf(buffer, p3-p2, p2+1);
	char *value = strtok(buffer, ",");
	if(value == NULL || strlen(value) < 1)
		return  NULL;
	
	if(value[0] == '\'' || value[0] == '\"')
	{
		int size = strlen(value);
		*ret = (char *)malloc(size-1);
		snprintf(*ret, size-1, value +1);
	}
	else
	{
		int size = strlen(value);
		*ret = (char *)malloc(size+1);
		snprintf(*ret, size+1, value);

	}
	while(value = strtok(NULL,","))
	{
		index ++;
		if(value[0] == '\'' || value[0] == '\"')
		{
			int size = strlen(value);
			char **p = ret+1;
			(*p) = (char *)malloc(size-1);
			snprintf((*p), size-1, value +1);
		}
		else
		{
			int size = strlen(value);
			*(ret+index) = (char *)malloc(size+1);
			snprintf(*(ret+index), size+1, value);
		}
		
	}
	return ret;
		
}

/*
 * insert sql str
 * schemal content
 * data file name
 *
 */

void do_insert(char *cmd, int *schemal, char *file)
{
	int size = 0;
	int index = 0;
	int columns = schemal[0];
	while(index < columns)
	{
		size += schemal[2*index+1];
		index ++;	
	} 
	printf("colume size %d\n", size);
	void *mem = malloc(size);
	memset(mem, 0, size);

	char **column = getColumns(cmd, columns); 
	index = 0;
	int position = 0;

	FILE *fp = fopen(file,"a+b");
	if(fp == NULL)
	{
		printf("open file faied");	
		return;
	}

	while(index < columns)
	{
		int column_size = schemal[2*index +1];
		if(schemal[2*index +2] == INT)
		{
			int value = atoi(*(column +index));	
			int *p = mem+position;
			*p = value;
			position += column_size;
		}
		else if(schemal[2*index +2] == CHAR)
		{
			sprintf((char*)(mem+position),"%s", *(column +index));	
			position += column_size;
		}
		index++;
	}
	fwrite(mem, size, 1, fp);
	fclose(fp);
	
}

/* get schemal file name from insert sql command */
char* get_insert_table_name(char *insertCmd)
{
	char *p = strstr(insertCmd, "values");
	if(p == NULL)
		return NULL;
	char *name = (char *)malloc(512);
	int size = p-insertCmd-12;
	if(size <1)
		return NULL;
	snprintf(name, size, insertCmd+12);
	//sprintf(name + size -1, "%s", ".schemal");
	return name;
}

/* read xxx.schemal get table schemal */
/* at most 100 column and 4096 byte size */
int* get_schemal(char *file)
{
	char buffer[4096];
	FILE *fp = fopen(file, "r+b");	
	if(fp ==NULL)
		printf("file open failed\n");
	int size = fread(buffer, 1, 4096,  fp);  
	if(size == 0)
	{
		fclose(fp);
		return NULL;
	}
	fclose(fp);
	int *schemal = (int *)malloc(101 *sizeof(int));
	schemal[0] = 0;
	int s_index = 1;
	int b_index = 0;
	int new = 1;
	while(b_index < size)
	{
		if(new)
		{
			schemal[s_index++] =  (0xFF & buffer[b_index +1]) << 8 | 0xFF & buffer[b_index];
			if(buffer[b_index+2] == 'i')
				schemal[s_index++] = INT;
			else if(buffer[b_index+2] == 'c')
				schemal[s_index++] = CHAR;
			else
				schemal[s_index++] = UNKNOW;
			b_index += 2;
			new = 0;
			schemal[0] ++;
		 }
		if(buffer[b_index++] == ';')
		{
			new = 1;
		}
	}
	return schemal;
}

void load_config()
{
        char *point = NULL;
        char *end = NULL;
        char *buffer = (char *)malloc(1024);

        FILE *fp = fopen(CONF_PATH, "r");
        if(fp == NULL)
        {
                printf("It Can;t find config file %s\n", CONF_PATH);
                g_datadir = "/home/svn/testpro/database/data";
                return;
        }
        else
        {
                printf("config file: %s\n", CONF_PATH);
        }
        fread(buffer,1024, 1, fp);
        point = strstr(buffer,"datadir=");
        if(point)
        {
                char enter[2];
                enter[0] = 0XA;
                enter[1] = 0;
                end = strstr(point,enter);
        }
        if(point == NULL || end == NULL)
        {
                printf("It can't get datadir from config file %s\n", CONF_PATH);
                g_datadir = "/home/svn/testpro/database/data";
                fclose(fp);
                return;
        }

        g_datadir = (char *) malloc( end - point - 7);
        strncpy(g_datadir, point+8, end - point - 8);
        printf("data dir : %s\n", g_datadir);
        fclose(fp);
}

